package com.dykj.fireFighting.server.base.fireEngine.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dykj.fireFighting.api.base.fireEngine.dto.FireEngineDto;
import com.dykj.fireFighting.api.base.fireEngine.entity.FireEngine;
import com.dykj.fireFighting.api.base.fireEngine.service.IFireEngineService;
import com.dykj.fireFighting.api.base.fireEngine.vo.*;
import com.dykj.fireFighting.api.base.system.entity.SysUser;
import com.dykj.fireFighting.api.base.system.service.ISysUserService;
import com.dykj.fireFighting.common.core.constant.WebsocketConstant;
import com.dykj.fireFighting.common.core.service.impl.BaseServiceImpl;
import com.dykj.fireFighting.common.core.utils.HttpClientResult;
import com.dykj.fireFighting.common.core.utils.HttpUtil;
import com.dykj.fireFighting.common.core.vo.PageVo;
import com.dykj.fireFighting.common.starter.redis.service.RedisService;
import com.dykj.fireFighting.server.base.fireEngine.mapper.FireEngineMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

/**
 * 消防车
 *
 * @Author JacksonTu
 * @Date 2021-11-12 13:47:40
 */
@Slf4j
@Service("FireEngineServiceImpl")
@DubboService
@Transactional(rollbackFor = Exception.class)
public class FireEngineServiceImpl extends BaseServiceImpl<FireEngineMapper, FireEngine> implements IFireEngineService {


    @Value("${EXLIVE.URL}")
    private String exliveUrl;
    @Value("${EXLIVE.VERSION}")
    private String exliveVersion;
    @Value("${EXLIVE.VLOGINSYSTEM}")
    private String exliveVloginSystem;
    @Value("${EXLIVE.LOADLOCATION}")
    private String exliveLoadLocation;
    @Value("${EXLIVE.LOADHISTORY}")
    private String exliveLoadHistory;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ISysUserService sysUserService;
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public PageVo<FireEngineVo> queryList(FireEngineDto fireEngineDto) {
        Map<String, Object> params = new HashMap<String, Object>();
        if (StringUtils.isNotBlank(fireEngineDto.getName())) {
            params.put("name", "%" + fireEngineDto.getName() + "%");
        }
        if (StringUtils.isNotBlank(fireEngineDto.getRescueId())) {
            params.put("rescueId", fireEngineDto.getRescueId());
        }
        Page page = new Page();
        // 设置当前页码
        page.setCurrent(fireEngineDto.getPage());
        // 设置页大小
        page.setSize(fireEngineDto.getLimit());
        return new PageVo<FireEngineVo>(this.baseMapper.queryList(page, params));
    }

    @Override
    public FireEngine getFireEngine(String carNum) {
        LambdaQueryWrapper<FireEngine> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FireEngine::getCarNum, carNum);
        wrapper.eq(FireEngine::getIsDel, 0);
        return this.baseMapper.selectOne(wrapper);
    }

    @Override
    public List<FireEngine> queryFireEngineByUnitId(String unitId) {
        LambdaQueryWrapper<FireEngine> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FireEngine::getUnitId, unitId);
        wrapper.eq(FireEngine::getIsDel, 0);
        return this.baseMapper.selectList(wrapper);
    }


    /**
     * 车辆登录
     *
     * @param name 车牌号
     * @param pwd
     * @return
     */
    public EXLIVEFireEngineVo vLoginSystem(String name, String pwd) {
        EXLIVEFireEngineVo exliveFireEngineVo = new EXLIVEFireEngineVo();
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("version", exliveVersion);
        params.put("method", exliveVloginSystem);
        params.put("name", name);
        params.put("pwd", pwd);

        String data = this.httpUtils(exliveVloginSystem, params);
        JSONObject resultData = JSONUtil.parseObj(data);
        if ((Boolean) resultData.get("success")) {
            Integer vid = (Integer) resultData.get("vid");
            String vKey = (String) resultData.get("vKey");
            if (vid != null && StringUtils.isNotBlank(vKey)) {
                int time = 60 * 60 * 24 * 7;
                log.info("{}的车辆ID:{},授权码:{}", name, vid, vKey);
                exliveFireEngineVo.setVId(vid);
                exliveFireEngineVo.setVKey(vKey);
                redisService.set(name, JSONUtil.toJsonPrettyStr(exliveFireEngineVo), (long) time);
            } else {
                log.error(name + "的车辆授权码为null");
            }
        } else {
            Object errorType = resultData.get("errorType");
            log.error(name + "的车辆授权码获取失败,errorType:" + errorType);
        }
        return exliveFireEngineVo;
    }

    /**
     * 车辆最新位置
     *
     * @param carNum 车牌号
     * @return
     */
    public EXLIVEFireEngineLocsVo loadLocation(String carNum) {
        //从redis中获取车辆授权码
        EXLIVEFireEngineLocsVo locs = new EXLIVEFireEngineLocsVo();
        if (StringUtils.isBlank(carNum)) {
            return locs;
        }
        String exliveString = (String) redisService.get(carNum);
        EXLIVEFireEngineVo exliveFireEngineVo = JSONUtil.toBean(exliveString, EXLIVEFireEngineVo.class);
        if (exliveFireEngineVo == null || StringUtils.isBlank(exliveFireEngineVo.getVKey())) {
            FireEngine fireEngine = this.getFireEngine(carNum);
            if (fireEngine != null && StringUtils.isNotBlank(fireEngine.getPwd())) {
                exliveFireEngineVo = this.vLoginSystem(fireEngine.getCarNum(), fireEngine.getPwd());
            } else {
                log.info("{}车辆信息查询失败!", carNum);
                return locs;
            }
        }

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("version", exliveVersion);
        params.put("method", exliveLoadLocation);
        params.put("vid", exliveFireEngineVo.getVId());
        params.put("vKey", exliveFireEngineVo.getVKey());

        String data = this.httpUtils(exliveLoadLocation, params);
        //String data = "{\"version\":1,\"success\":true,\"locs\":[{\"id\":4103747,\"name\":\"辽HB929 \",\"recvtime\":1375867746000,\"gpstime\":1375867680000,\"lat\":40.77228,\"lng\":122.27882,\"lat_xz\":0.001645,\"lng_xz\":0.005182,\"state\":\"防劫报警 停车超时报警(7h11m)? \",\"speed\":0,\"direct\":336,\"temp\":-50,\"oil\":0,\"oilMN1\":0,\"oilMN2\":0,\"distance\":62.4,\"totalDis\":22559.44,\"av\":\"1\",\"info\":\"辽宁省 营口市 大石桥市 加油站西南1673米 [1]\",\"vhcofflinemin\":10,\"stopDefDis\":0,\"stopDefLat\":0,\"stopDefLng\":0,\"temp1\":\"0.0\",\"temp2\":\"0.0\",\"temp3\":\"0.0\",\"temp4\":\"0.0\"}]}";
        JSONObject resultData = JSONUtil.parseObj(data);
        if ((Boolean) resultData.get("success")) {
            JSONArray locsArray = (JSONArray) resultData.get("locs");
            log.info("{}车辆最新位置信息:{}", carNum, data);
            if (!JSONUtil.isNull(locsArray)) {
                List<EXLIVEFireEngineLocsVo> locsList = JSONUtil.toList(locsArray, EXLIVEFireEngineLocsVo.class);
                locs = locsList.get(0);
            }
        } else {
            Object errorType = resultData.get("errorType");
            log.error("{}车辆最新位置信息获取失败,errorType:{}", carNum, errorType);
        }
        return locs;
    }

    /**
     * 轨迹回放
     *
     * @param carNum
     * @param bTime
     * @param eTime
     * @return
     */
    public List<EXLIVEFireEngineLocsHistoryVo> loadHistory(String carNum, Long bTime, Long eTime) {
        //从redis中获取车辆授权码
        List<EXLIVEFireEngineLocsHistoryVo> locsHistoryList = new ArrayList<>();
        if (StringUtils.isBlank(carNum) || bTime == null || eTime == null) {
            return locsHistoryList;
        }
        String exliveString = (String) redisService.get(carNum);
        EXLIVEFireEngineVo exliveFireEngineVo = JSONUtil.toBean(exliveString, EXLIVEFireEngineVo.class);
        if (exliveFireEngineVo == null || StringUtils.isBlank(exliveFireEngineVo.getVKey())) {
            FireEngine fireEngine = this.getFireEngine(carNum);
            if (fireEngine != null && StringUtils.isNotBlank(fireEngine.getPwd())) {
                exliveFireEngineVo = this.vLoginSystem(fireEngine.getCarNum(), fireEngine.getPwd());
            } else {
                log.info("{}车辆信息查询失败!", carNum);
                return locsHistoryList;
            }
        }

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("version", exliveVersion);
        params.put("method", exliveLoadHistory);
        params.put("vid", exliveFireEngineVo.getVId());
        params.put("vKey", exliveFireEngineVo.getVKey());
        params.put("bTime", bTime);
        params.put("eTime", eTime);
        HttpClientResult result = null;

        String data = this.httpUtils(exliveLoadLocation, params);
        //String data = "{\"version\":1,\"success\":true,\"history\":[{\"av\":\"1\",\"dir\":330,\"dis\":0,\"gpst\":\"2013-08-03 00:00:30\",\"id\":1,\"lat\":40.662804,\"lat_xz\":0.001645,\"lng\":122.250465,\"lng_xz\":0.005182,\"oil\":0,\"p1\":0,\"p2\":0,\"photo\":\"\",\"posinfo\":\"辽宁省 营口市 站前区 桂丰园小区西105米 [1]\",\"recvt\":\"2013-08-03 00:01:29\",\"state\":\"防劫报警 停车(24m)\",\"temp\":-50,\"totaldistance\":22250.303,\"veo\":0}]}";
        JSONObject resultData = JSONUtil.parseObj(data);
        if ((Boolean) resultData.get("success")) {
            JSONArray locsHistory = (JSONArray) resultData.get("history");
            log.info("{}车辆轨迹回放信息:{}", carNum, locsHistory);
            if (!JSONUtil.isNull(locsHistory)) {
                locsHistoryList = JSONUtil.toList(locsHistory, EXLIVEFireEngineLocsHistoryVo.class);
            }
        } else {
            Object errorType = resultData.get("errorType");
            log.error("{}车辆最新位置信息获取失败,errorType:{}", carNum, errorType);
        }
        return locsHistoryList;
    }

    @Override
    public void batchLoadLocation() {
        log.info("===========实时查询消防车最新位置开始===============");

        Set<Object> userIdArr = redisService.sGet("FireEngineJob");
        if (CollectionUtil.isNotEmpty(userIdArr)) {
            log.info("查询用户:{}", userIdArr.toString());
            for (Object userId : userIdArr) {
                String unitId = (String) redisService.get("userId" + userId.toString());
                if (StringUtils.isBlank(unitId)) {
                    SysUser sysUser = sysUserService.getById(userId.toString());
                    unitId = sysUser.getEnterpriseId().toString();
                    redisService.set("userId" + userId.toString(), unitId);
                }
                List<FireEngine> fireEnginesList = this.queryFireEngineByUnitId(unitId);
                this.fireEngineThreadPoolTask(userId.toString(), fireEnginesList);
            }
        }

    }

    /**
     *
     */
    @Async("threadPoolTaskExecutor")
    public void fireEngineThreadPoolTask(String userId, List<FireEngine> fireEnginesList) {
        log.info("查询用户:{},消防车数量:{}", userId, fireEnginesList.size());
        for (FireEngine fireEngines : fireEnginesList) {
            EXLIVEFireEngineLocsVo fireEngineLocsVo = this.loadLocation(fireEngines.getCarNum());
            FireEngineMessage fireEngineMessage = new FireEngineMessage();
            fireEngineMessage.setUserId(userId);
            fireEngineMessage.setCmd(WebsocketConstant.CMD_ENGINE);
            fireEngineMessage.setMessage(JSONUtil.toJsonStr(fireEngineLocsVo));
            redisService.convertAndSend("channel:fireEngineMessage", fireEngineMessage);
        }
    }

    private String httpUtils(String method, Map<String, Object> params) {
        HttpClientResult result = null;

        try {
            result = HttpUtil.postWithForm(exliveUrl, null, params);
            JSONObject resultObj = JSONUtil.parseObj(result);
            log.info("EXLIVE开放平台接口方法:{},请求返回结果:{},{}", method, (Integer) resultObj.get("code"), (String) resultObj.get("data"));
            if (200 == (Integer) resultObj.get("code")) {
                return (String) resultObj.get("data");
            }
        } catch (IOException e) {
            log.error("EXLIVE开放平台接口方法:{},请求失败:{}", method, e.getMessage());
            e.printStackTrace();
        }
        return "";
    }

}
